using System;
using System.Collections.Generic;
using System.Reflection;

using NUnit.Framework;

using WCSFContrib.Extensions.EventBroker;

namespace WCSFContrib.Extensions.Tests.EventBroker
{
	[TestFixture]
	public class EventBrokerSanityCheckTests
	{
		private EventBrokerSanityCheck eventBrokerSanityCheck;

		[TestFixtureSetUp]
		public void TestFixtureSetUp()
		{
			eventBrokerSanityCheck = new EventBrokerSanityCheck();
		}

		[Test]
		public void GetCustomAttributesFromMember_OneAttribute()
		{
			IEnumerable<EventSubscriptionAttribute> result = eventBrokerSanityCheck.GetCustomAttributesFromMember<EventSubscriptionAttribute>(
				 GetType().GetMethod("TestmethodWithOneAttribute", BindingFlags.NonPublic | BindingFlags.Instance));
			int i = 0;
			foreach (EventSubscriptionAttribute attribute in result)
			{
				i++;
			}
			Assert.AreEqual(1, i);
		}

		[Test]
		public void GetCustomAttributesFromMember_TwoAttributes()
		{
			eventBrokerSanityCheck = new EventBrokerSanityCheck();
			IEnumerable<EventSubscriptionAttribute> result = eventBrokerSanityCheck.GetCustomAttributesFromMember<EventSubscriptionAttribute>(
				 GetType().GetMethod("TestMethodWithTwoAttributes", BindingFlags.NonPublic | BindingFlags.Instance));
			int i = 0;
			foreach (EventSubscriptionAttribute attribute in result)
			{
				i++;
			}
			Assert.AreEqual(2, i);
		}

		[Test]
		public void GetCustomAttributesFromMember_NoAttributes()
		{
			eventBrokerSanityCheck = new EventBrokerSanityCheck();
			IEnumerable<EventSubscriptionAttribute> result = eventBrokerSanityCheck.GetCustomAttributesFromMember<EventSubscriptionAttribute>(
				 GetType().GetMethod("TestMethodWithNoAttributes", BindingFlags.NonPublic | BindingFlags.Instance));
			int i = 0;
			foreach (EventSubscriptionAttribute attribute in result)
			{
				i++;
			}
			Assert.AreEqual(0, i);
		}

		[Test]
		public void GetCustomAttributesFromMember_AskForWrongAttribute()
		{
			eventBrokerSanityCheck = new EventBrokerSanityCheck();
			IEnumerable<EventPublicationAttribute> result = eventBrokerSanityCheck.GetCustomAttributesFromMember<EventPublicationAttribute>(
				 GetType().GetMethod("TestmethodWithOneAttribute", BindingFlags.NonPublic | BindingFlags.Instance));
			int i = 0;
			foreach (EventPublicationAttribute attribute in result)
			{
				i++;
			}
			Assert.AreEqual(0, i);
		}

		[Test]
		public void GetCustomAttributesFromMember_Inherited()
		{
			eventBrokerSanityCheck = new EventBrokerSanityCheck();
			IEnumerable<EventPublicationAttribute> result = eventBrokerSanityCheck.GetCustomAttributesFromMember<EventPublicationAttribute>(
				 typeof(TestOfInheritence).GetEvent("anEvent"));
			int i = 0;
			foreach (EventPublicationAttribute attribute in result)
			{
				i++;
			}
			Assert.AreEqual(0, i);
		}

		[Test]
		public void FindEventsOnTestClass()
		{
			MemberReference<EventInfo>[] expectedEvents = new MemberReference<EventInfo>[2]
                {
                    new MemberReference<EventInfo>("foo", typeof (TestPublisher).GetEvent("anEvent")),
                    new MemberReference<EventInfo>("bar", typeof (TestPublisher).GetEvent("anotherEvent"))
                };
			IEnumerable<MemberReference<EventInfo>> results = eventBrokerSanityCheck.GetPublishingEvents(typeof(TestPublisher));

			List<MemberReference<EventInfo>> listOfResults = new List<MemberReference<EventInfo>>(results);
			Assert.AreEqual(expectedEvents[0].Topic, listOfResults[0].Topic);
			Assert.AreSame(expectedEvents[0].Info, listOfResults[0].Info);
			Assert.AreEqual(expectedEvents[1].Topic, listOfResults[1].Topic);
			Assert.AreSame(expectedEvents[1].Info, listOfResults[1].Info);
		}

		[Test]
		public void FindsubscriptionsOnTestClass()
		{
			MemberReference<MethodInfo>[] expectedMethods = new MemberReference<MethodInfo>[5]
                {
                    new MemberReference<MethodInfo>("42", typeof (TestSubscriber).GetMethod("NoParameters")),
                    new MemberReference<MethodInfo>("foo", typeof (TestSubscriber).GetMethod("NoParameters")),
                    new MemberReference<MethodInfo>("bar", typeof (TestSubscriber).GetMethod("OneParameter")),
                    new MemberReference<MethodInfo>("bas", typeof (TestSubscriber).GetMethod("TwoParameters")),
                    new MemberReference<MethodInfo>("43", typeof (TestSubscriber).GetMethod("MyOwnSubscription"))
                };
			IEnumerable<MemberReference<MethodInfo>> results = eventBrokerSanityCheck.GetSubscribingMethods(typeof(TestSubscriber));

			List<MemberReference<MethodInfo>> listOfResults = new List<MemberReference<MethodInfo>>(results);
			Assert.AreEqual(5, listOfResults.Count);
			for (int i = 0; i < 4; i++)
			{
				Assert.AreEqual(expectedMethods[i].Topic, listOfResults[i].Topic);
				Assert.AreSame(expectedMethods[i].Info, listOfResults[i].Info);
			}
		}

		[EventSubscription("bar")]
		private void TestmethodWithOneAttribute()
		{ }

		[EventSubscription("bar")]
		[EventSubscription("42")]
		private void TestMethodWithTwoAttributes()
		{
			TestMethodWithNoAttributes();
		}

		private void TestMethodWithNoAttributes()
		{ }

		private interface IAmAPublisher
		{
			[EventPublicationAttribute("foo")]
			event EventHandler anEvent;
		}
		private interface IAmAPublisher2 : IAmAPublisher
		{ }

		private class TestPublisher : IAmAPublisher
		{
			public event EventHandler anEvent;
			[EventPublication("bar")]
			public event EventHandler anotherEvent;

			public void callEvents()
			{
				anEvent.Invoke(this, EventArgs.Empty);
				anotherEvent.Invoke(this, EventArgs.Empty);
			}
		}

		private interface IAmASubscriber
		{
			[EventSubscription("foo")]
			void NoParameters();
			[EventSubscription("bar")]
			void OneParameter(string key);
			[EventSubscription("bas")]
			void TwoParameters(object sender, EventArgs e);
		}

		private class TestSubscriber : IAmASubscriber
		{
			[EventSubscription("42")]
			public void NoParameters()
			{
				throw new NotImplementedException();
			}

			public void OneParameter(string key)
			{
				throw new NotImplementedException();
			}

			public void TwoParameters(object sender, EventArgs e)
			{
				throw new NotImplementedException();
			}

			[EventSubscription("43")]
			public void MyOwnSubscription()
			{
				throw new NotImplementedException();
			}
		}

		private class TestOfInheritence : IAmAPublisher2
		{
			public event EventHandler anEvent;
			public void Test()
			{
				anEvent.Invoke(this, EventArgs.Empty);
			}
		}
	}
}